#include "SDLDrawing.h"
#include "objectManagement.h"
#include <SDL_ttf.h>

//! \brief Initializes the drawing subsystem parameters
//!
//! \param baseMat The base RGB color matrix
//! \param sz The size of the matrix
//! \return Initialized drawing parameters
//!
DrawParameters initDrawing(Pixel** baseMat, Taille sz)
{
    DrawParameters drawParams;

    PixelHSI d2 = {0,0,0};
    PixelHSI** matHSI = createMatrix(sz, d2);
    applyMatrix(baseMat, matHSI, sz, RGBtoHSI);

    drawParams.drawMode.mainMode = OBJECT;
    drawParams.drawMode.drawSkel = SKULL_NO_DRAW;
    drawParams.drawMode.drawIsobar = false;
    drawParams.mat = baseMat;
    drawParams.matHSI = matHSI;
    drawParams.sz = sz;

    return drawParams;
}

//! \brief Prints a matrix onto a SDL-type surface
//!
//! \param mat A pixel matrix to draw
//! \param size The size of mat
//! \param screen A surface to draw the matrix onto
//!
//!
void matriceAff(Pixel** mat, Taille size, SDL_Surface* screen, bool transparency, Pixel* transpPixel)
{
    SDL_Surface* surface = SDL_CreateRGBSurface(SDL_SWSURFACE, size.nbrcolumn, size.nbrlign, 24, 0xff0000,0x00ff00,0x0000ff,0x0);
    int li, col;

    SDL_LockSurface(surface);
    Uint8* pixels = (Uint8*)surface->pixels;

    for (li = 0 ; li < size.nbrlign ; li++)
    {
        for (col = 0 ; col < size.nbrcolumn ; col++)
        {
            setSDLPixelfromPixel(mat[li][col], pixels);
            pixels += 3;
        }
        pixels += (surface->pitch - 3*col);
    }
    SDL_UnlockSurface(surface);

    if(transparency)
    {
        SDL_SetColorKey(surface, SDL_SRCCOLORKEY, SDL_MapRGB(surface->format, transpPixel->r, transpPixel->g, transpPixel->b));
    }

    SDL_BlitSurface(surface, NULL, screen, NULL);
    SDL_FreeSurface(surface);
}

//! \brief Prints a boolean matrix (mask) onto a SDL-type surface
//!
//! \param mask A boolean matrix to draw
//! \param size The size of mask
//! \param screen A surface to draw the matrix onto
//!
//!
void maskAff(bool** mask, Taille size, SDL_Surface* screen, bool transparency)
{
    Pixel fillPx = {0,0,0}, treated = {255,255,255};
    int i, j;
    Pixel** pxMatrix = createMatrix(size, fillPx);
    for (i = 0 ; i < size.nbrlign ; i++)
    {
        for (j = 0 ; j < size.nbrcolumn ; j++)
        {
            if (mask[i][j]) {pxMatrix[i][j] = treated;} // we white out the treated parts of the mask
        }
    }
    matriceAff(pxMatrix ,size, screen, transparency, &fillPx);
    freeMatrix(pxMatrix, size);
}

//! \brief Hue drawing protocol
//!
//! \param px A Pixel in HSI format
//! \return A Pixel
//!
//!
Pixel Hvalue(PixelHSI px)
{
    Pixel newPx;
    newPx.r = (Uint8)(px.H / 1.5);
    newPx.g = (Uint8)(px.H / 1.5);
    newPx.b = (Uint8)(px.H / 1.5);
    return newPx;
}

//! \brief Saturation drawing protocol
//!
//! \param px A Pixel in HSI format
//! \return A Pixel
//!
//!
Pixel Svalue(PixelHSI px)
{
    Pixel newPx;
    newPx.r = (Uint8)(px.S);
    newPx.g = (Uint8)(px.S);
    newPx.b = (Uint8)(px.S);
    return newPx;
}

//! \brief Intensity drawing protocol
//!
//! \param px A Pixel in HSI format
//! \return A Pixel
//!
//!
Pixel Ivalue(PixelHSI px)
{
    Pixel newPx;
    newPx.r = (Uint8)(px.I);
    newPx.g = (Uint8)(px.I);
    newPx.b = (Uint8)(px.I);
    return newPx;
}

//! \brief Prints every object onto a SDL-type surface
//!
//! \param objs An object manager
//! \param size The size of the object matrix
//! \param screen A surface to draw the objects onto
//!
//!
void objAff(ObjectManager* objs, Taille size, SDL_Surface* screen)
{
    Pixel noObject = {0,0,0};
    Pixel** pxMatrix = createMatrix(size, noObject);
    int li, col;

    for (li = 0; li < size.nbrlign; li++)
    {
        for (col = 0; col < size.nbrcolumn; col++)
        {
            if(objs->getMat()[li][col] != NO_OBJECT)
            {
                pxMatrix[li][col] = (objs->getObj(objs->getMat()[li][col]))->getMainRGB();
            }
        }
    }
    matriceAff(pxMatrix ,size, screen);
    freeMatrix(pxMatrix, size);
}

//! \brief Prints isobars onto a SDL-type surface
//!
//! \param objs An object manager
//! \param screen A surface to draw the isobarycenters onto
//!
//!
void drawIsobar(ObjectManager* objs, SDL_Surface* screen)
{
    SDL_Surface* point = SDL_CreateRGBSurface(SDL_HWSURFACE, 3, 3, 32, 0,0,0,0);
    SDL_FillRect(point, NULL, SDL_MapRGB(point->format, 255, 255, 255));
    SDL_Rect rect;
    std::vector<Object*> t_objects = objs->getObjs();

    for(std::vector<Object*>::iterator it = t_objects.begin(); it!=t_objects.end(); it++)
    {
        rect.x = (*it)->getIsobar().column;
        rect.y = (*it)->getIsobar().lign;
        SDL_BlitSurface(point, NULL, screen, &rect);
    }
    SDL_FreeSurface(point);
}

//! \brief Prints the object count onto a SDL-type surface
//!
//! \param count The object count
//! \param screen A surface to draw the object count onto
//!
//!
void objCountAff(int count, SDL_Surface* screen)
{
    SDL_Rect pos = {10,10};
    char nombre[50];
    sprintf(nombre, "Il y a %d objets.", count);
    textAff(nombre, pos, screen);
}

//! \brief Prints the drawing state onto a SDL-type surface
//!
//! \param state The drawing state name
//! \param screen A surface to draw the text onto
//!
//!
void stateAff(const char* state, SDL_Surface* screen)
{
    SDL_Rect pos = {10, (short)(screen->h - 40)};
    textAff(state, pos, screen);
}

//! \brief Prints text onto a SDL-type surface
//!
//! \param text A text to draw
//! \param pos A position where to print the text
//! \param screen A surface to draw the text onto
//!
//!
void textAff(const char* text, SDL_Rect pos, SDL_Surface* screen)
{
    TTF_Font *police = TTF_OpenFont("times.ttf", 30);
    SDL_Color col = {0, 0, 0};
    //SDL_Color col2 = {255, 255, 255};

    SDL_Surface* texteSfc = TTF_RenderText_Blended(police, text, col);
    SDL_BlitSurface(texteSfc, NULL, screen, &pos);
    //SDL_Rect pos2 = {pos.x + texteSfc->w + 5, pos.y};
    SDL_FreeSurface(texteSfc);

    /*texteSfc = TTF_RenderText_Blended(police, text, col2);
    SDL_BlitSurface(texteSfc, NULL, screen, &pos2);
    SDL_FreeSurface(texteSfc);*/

    TTF_CloseFont(police);
}

//! \brief Saves the result image into a .bmp file
//!
//! \param screen A surface to print into the .bmp file
//! \param L The Luminance threshold
//! \param ab The Chromatic threshold
//!
//!
void saveResult(SDL_Surface* screen, int L, int ab)
{
    char str[50];
    sprintf(str, "Result (%d,%d).bmp", L, ab);
    SDL_SaveBMP(screen, str);
}

//! \brief Main drawing function
//!        Draws everything based on the drawing parameters
//!
//! \param screen A surface to draw onto
//! \param objs An object manager
//! \param drawParams The drawing parameters
//!
//!
void drawScene(SDL_Surface* screen, ObjectManager* objs, DrawParameters drawParams)
{
    SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 0, 0, 0));
    switch(drawParams.drawMode.mainMode)
    {
    case OBJECT:
        objAff(objs, drawParams.sz, screen);                   // Source selection
        stateAff("Objects", screen);
        break;
    case ORIGINAL:
        matriceAff(drawParams.mat, drawParams.sz, screen);
        stateAff("Original", screen);
        break;
    case HUE:
        matrixValue(drawParams.matHSI, drawParams.sz, &Hvalue, screen);
        stateAff("Hue", screen);
        break;
    case SATURATION:
        matrixValue(drawParams.matHSI, drawParams.sz, &Svalue, screen);
        stateAff("Saturation", screen);
        break;
    case VALUE:
        matrixValue(drawParams.matHSI, drawParams.sz, &Ivalue, screen);
        stateAff("Value", screen);
        break;
    }
    objCountAff(objs->getCount(), screen);
    if(drawParams.drawMode.drawSkel > 0) maskAff(objs->getSkeletonMasks(), drawParams.sz, screen, drawParams.drawMode.drawSkel-1);
    if(drawParams.drawMode.drawIsobar) drawIsobar(objs, screen);


    SDL_Flip(screen);
}

